#include <GL/glut.h>

#include "Camera.h"
#include "Terrain.h"
#include "Md2Model.h"
#include "Timer.h"
#include "TextureProcessor.h"


Camera camera;
Terrain terrain;

// Centre of the Screen
int CenterX(400), CenterY(300);

Model Ogre, Weapon;

void Initialize()
{
	terrain.skip = 8;
	terrain.Create("Terrain/heightField.raw", "Terrain/texture.raw", 1024, 1024);

	Ogre.LoadModel("Models/Ogros.md2");
	Ogre.LoadSkin("Models/igdosh.pcx");
	Ogre.SetAnim(1);
	Ogre.ScaleModel(0.25);
	Weapon.LoadModel("Models/Weapon.md2");
	Weapon.LoadSkin("Models/Weapon.pcx");
	Weapon.SetAnim(1);
	Weapon.ScaleModel(0.25);

	CTimer::GetInstance()->Initialize();
	CTextureManager::GetInstance()->Initialize();
}

void renderScene()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glClearDepth(1);

	glLoadIdentity();
	gluLookAt(camera.Position.x, camera.Position.y, camera.Position.z, //  Camera position
			camera.Target.x, camera.Target.y, camera.Target.z, // Target position
			0.0f, 1.0f, 0.0f); // Up vector

	terrain.Render();

	CTimer::GetInstance()->Update();
	float timesec = CTimer::GetInstance()->GetTimeMSec() / 1000.0;


	glEnable( GL_TEXTURE_2D );
	glPushMatrix();
	glTranslatef(3, 0, 30);
	glRotatef(180, 0, 1, 0);
	Ogre.DrawModel(timesec/2);
	Weapon.DrawModel(timesec/2);
	glPopMatrix();
	glDisable( GL_TEXTURE_2D );

	glPushMatrix();
	glTranslatef(0, 0, 5);
	glutSolidCube(1);
	glPopMatrix();

	glPushMatrix();
	glTranslatef(3, 0, 5);
	glutSolidCube(1);
	glPopMatrix();

	glutSwapBuffers();
}

void changeSize(int w, int h)
{

	// Prevent a divide by zero, when window is too short
	// (you can't make a window of zero width).
	if (h == 0)
		h = 1;

	float ratio = 1.0 * w / h;

	// Update the Centre of the Screen
	CenterX = w / 2;
	CenterY = h / 2;

	// Reset the coordinate system before modifying
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// Set the viewport to be the entire window
	glViewport(0, 0, w, h);

	// Set the correct perspective.
	gluPerspective(45, ratio, 0.1, 1000);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(camera.Position.x, camera.Position.y, camera.Position.z, //  Camera position
			camera.Target.x, camera.Target.y, camera.Target.z, // Target position
			0.0f, 1.0f, 0.0f); // Up vector
}

void handlePassiveMotion(int x, int y)
{
	if (x > 400)
	{
		camera.Rotation.y -= 1;
		camera.Update();
		glutWarpPointer(400, 300);
	}
	else if (x < 400)
	{
		camera.Rotation.y += 1;
		camera.Update();
		glutWarpPointer(400, 300);
	}

	if (y > 300)
	{
		camera.Rotation.x -= 1;
		camera.Update();
		glutWarpPointer(400, 300);
	}
	else if (y < 300)
	{
		camera.Rotation.x += 1;
		camera.Update();
		glutWarpPointer(400, 300);
	}
}

void handleKeyInput(unsigned char key, int x, int y)
{
	switch (key)
	{
		case 27:
			exit(0);
			break;
		case 'w':
			camera.Position += camera.Forward;
			camera.Update();
			break;
		case 's':
			camera.Position -= camera.Forward;
			camera.Update();
			break;
		case 'a':
			camera.Position += camera.Left;
			camera.Target += camera.Left;
			camera.Update();
			break;
		case 'd':
			camera.Position += camera.Right;
			camera.Target += camera.Right;
			camera.Update();
			break;
	}
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);

	// Window position and size
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(800, 600);

	// Create the Window
	glutCreateWindow("First Person Camera");

	Initialize();

	// Setting the display and idle functions
	glutDisplayFunc(renderScene);
	glutIdleFunc(renderScene);

	// Setting the reshape function
	glutReshapeFunc(changeSize);

	// Setting the Mouse Motion functions
	glutMotionFunc(handlePassiveMotion);
	glutPassiveMotionFunc(handlePassiveMotion);

	// Setting the Keyboard function
	glutKeyboardFunc(handleKeyInput);

	// Enabling Depth Testing
	glEnable(GL_DEPTH_TEST);

	glutSetCursor(GLUT_CURSOR_NONE);

	// Enters an infinite loop until the application exits
	glutMainLoop();
	return 0;
}
